package coalition.types;

import iteration.RecursiveAccess;

import java.util.HashMap;
import java.util.List;
import java.util.Vector;

import population.Population;

import combinations.Combinations;

import utils.Util;

import coalition.Coalition;
import coalition.CoalitionFormation;

public class OneFixedAndOneDisjunctionCoalition implements CoalitionType{

	//int determiningAttributeIndex;
	//int fixedAtributeIndex;
	//int fixedAttributeValue;
	
	int maximumDisjunctiveSize;
	int[] dimensionSizes;
	Population population;
	HashMap<Integer, Combinations> combinationSchemes;
	
	public OneFixedAndOneDisjunctionCoalition(CoalitionFormation coalitionFormation,
			HashMap<Integer, Combinations> combinationSchemes
			//, int determiningAttributeIndex,
			//int fixedAtributeIndex, int fixedAttributeValue
			){
		//this.determiningAttributeIndex = determiningAttributeIndex;
		//this.fixedAtributeIndex = fixedAtributeIndex;
		//this.fixedAttributeValue = fixedAttributeValue;
		
		this.maximumDisjunctiveSize = coalitionFormation.getMaximumDisjunctiveSize();
		this.dimensionSizes = coalitionFormation.getDimensionSizes();
		this.population = coalitionFormation.getPopulation();
		this.combinationSchemes = combinationSchemes;
	}
	
	//this is the case of coalitions in which two
	//attributes are used to specify the coalition.
	//all combinations of values for one attribute, the "determining" attribute, are
	//legal except for the empty set, a coalition with no people,
	//the full set IS allowed since we have the fixed attribute to
	//prevent the resulting coalition from encompassing the universal population
	//the "fixed attribute" can take on only one value
	@Override
	public List<Coalition> getCoalitions(){
		
		//List<List<Integer>> attributeIndexcombinations = getCombinations(dimensionSizes.length, 2);
		
		List<Coalition> coalitions = new Vector<Coalition>();
		//pick an attribute
		for(int i = 0; i < dimensionSizes.length; i++){//iterate over the determining attribute
			for(int j = 0; j < dimensionSizes.length; j++){//iterate over fixed attribute
				if(j == i) continue;//determining and fixed attribute can't be the same
				for(int k = 0; k < dimensionSizes[j]; k++){//iterate over value of fixed attribute
					Vector<Coalition> coalitionsWithAttributeSet =
						getAllCoalitionsByDeterminingAtttributeAndFixedAttribute(i, j, k);
					coalitions.addAll(coalitionsWithAttributeSet);
				}
			}
		}
		return coalitions;
	}	
	
	public Vector<Coalition> getAllCoalitionsByDeterminingAtttributeAndFixedAttribute(
			int determiningAttributeIndex,
			int fixedAtributeIndex, int fixedAttributeValue		
	) {
		List<List<Integer>> attributeValueCombinations;
		if(maximumDisjunctiveSize == -1)
			attributeValueCombinations = combinationSchemes.get(determiningAttributeIndex).getCombinations(dimensionSizes[determiningAttributeIndex]);
		else
			attributeValueCombinations = 
				combinationSchemes.get(determiningAttributeIndex).getCombinationsUpToSize(dimensionSizes[determiningAttributeIndex], maximumDisjunctiveSize);
		
		Vector<Coalition> coalitions = new Vector<Coalition>();
		
		//form a coalition for each combination of attribute values
		for(List<Integer> attributeValueCombination : attributeValueCombinations){
			//disallow the empty set but allow the full set
			//since we have the fixed attribute to prevent the
			//resulting coalition from encompassing the universal population
			if(attributeValueCombination.size() == 0
					
					//here we are making sure that for the case when the determining attribute
					//value combination has only one value that we do not calculate the same
					//coalition twice since a determining attribute value combination with 
					//only one value is the same as a fixed attribute value
					//we use index ordering of attributes to make sure two
					//single attributes are only used in one coalition calculation
					|| ( 
							attributeValueCombination.size() == 1  && 
							//this is a bug:  (attributeValueCombination.get(0) < fixedAtributeIndex) 
							//only use one of two cases when disjunctive combination has size
							//one, because in that case it is like a fixed attribute index
							//and we end up with symmetry between the disjunctive index and the
							//single value index
							determiningAttributeIndex < fixedAtributeIndex
							
					) 
					//|| attributeValueCombination.size() == dimensionSizes[determiningAttributeIndex]                                  
			                          			) continue;			
			List<int[]> sectorsInvolved = new Vector<int[]>();
			List<int[]> sectorsReducedRepresentation = new Vector<int[]>();
			//find the population sectors for each attribute value in
			//the attribute value combination for this coalition
			for(int attributeValue : attributeValueCombination){
				//generate array with -1's in all places except the determining attribute index and 
				//the fixed attribute index
				int[] indices = 
					Util.getIndexArrayWithTwoValues(dimensionSizes.length, determiningAttributeIndex, attributeValue,
							fixedAtributeIndex, fixedAttributeValue	
					);
				//calculate all sectors in this coalition
				List<int[]> coalitionSubList = 
					RecursiveAccess.generateAllPermutations(indices, dimensionSizes);
				sectorsInvolved.addAll(coalitionSubList);
				sectorsReducedRepresentation.add(indices);
			}
			
			Coalition coalition = new Coalition(population, sectorsInvolved, sectorsReducedRepresentation);
			coalitions.add(coalition);
		}
		return coalitions;
	}

}
